#include "liste.h"

// Pretty printing of a mac address gave in the intercepted packets
// e.g. a table of 6 Bytes
void print_mac(u_char s[6]) {
    int i;
    for (i=0; i<5; i++) {
        printf("%02x:", s[i]);
    }
    printf("%02x\n", s[5]);
}

// Returns 1 if t2 is older than t1
int diffTimeval(struct timeval t1 , struct timeval t2) {
    // TODO: Diff between 2 timevals
    return ((t1.tv_sec * 1000000 + t1.tv_usec) > (t2.tv_sec * 1000000 + t2.tv_usec));
}

//RSSI

// adds the RSSI sample (e.g. the RSSI value and its expiration date, that is
// the current date more 1 second) for the device pointed by l.
void add_rssi_sample (DeviceList * l , int rssi_value) {
    RssiList * new_rl = (RssiList *) malloc(sizeof(RssiList));
    new_rl->rl_rssi_value = rssi_value;
    
    new_rl->rl_next = l->dl_rssi_list;
	
    gettimeofday(&(new_rl->rl_date), NULL);
    new_rl->rl_date.tv_sec += 1;
    l->dl_rssi_list = new_rl;
}


void clear_rssi_list (RssiList * l) {
    RssiList * courant = l;
    RssiList * tmp;
    while (courant != NULL) {
        tmp = courant;
        courant = courant->rl_next;
        free(tmp);
    }
    free(courant);
}

// delete every RssiList of the chain list starting from the one pointed by rssi
void clear_rssiList_from(RssiList * rssi) {
    RssiList * to_delete = NULL;
    while (rssi != NULL) {
        to_delete = rssi;
        rssi = rssi->rl_next;
        free(to_delete);
    }
    free(rssi);
}

//void delete_outdated(DeviceList * l , struct timeval current_time) {
//    //TODO: Parcours devicelist and compare timeval
//    DeviceList * courantDevice = NULL;
//    RssiList * courantRssi = NULL;
//    RssiList * tmpRssi = NULL;
//    courantDevice = l;
//    while (courantDevice != NULL) {
//        courantRssi = courantDevice->dl_rssi_list;
//        while (courantRssi != NULL) {
//            if (diffTimeval(current_time, courantRssi->rl_date)) {
//                clear_rssi_list(courantRssi);
//                if (tmpRssi != NULL) 
//                    tmpRssi->rl_next = NULL;
//                else 
//                    courantDevice->dl_rssi_list = NULL;
//            }
//            tmpRssi = courantRssi;
//            courantRssi = courantRssi->rl_next;
//        }
//        courantDevice = courantDevice->dl_next;
//    }
//}


// deletes all RSSIs of all devices that have an expiration date inferior than
// current_time
void delete_outdated(DeviceList *l, struct timeval current_time) {
    DeviceList * device = l;
    RssiList * rssi = NULL;
    RssiList * prev_rssi = NULL;
    int sortir = 0;
    //we go through all the devices
    while (device != NULL) {
        sortir = 0;
        //for each devices we go through all RSSIs
        //we delete all RSSIs from the first one which is too old
        rssi = device->dl_rssi_list;
        prev_rssi = NULL;
        while (rssi != NULL && sortir==0) {
            if (diffTimeval(current_time, rssi->rl_date)) {
                //the rssi is too old
                //we delete it and all that follow
                clear_rssiList_from(rssi);
                //we make the last rssi in the list points to NULL
                if (prev_rssi != NULL) {
                    prev_rssi->rl_next = NULL;
                } else {
                    //in that case, there is no rssi in the list
                    device->dl_rssi_list = NULL;
                }
                sortir = 1;
            } else {
                prev_rssi = rssi;
                rssi = rssi->rl_next;
            }
        }
        device = device->dl_next;
    }
}

// compares two mac addresses (tables of 6 bytes)
// returns 0 if they are equals, -1 if s1 is inferior to s2, and 1 else
int maccmp(char s1[6], char s2[6]) {
    int i;
    for (i=0; i<6; i++) {
        //printf("%02x %02x %d %d\n", s1[i], s2[i], s1[i]<s2[i], s1[i]>s2[i]);
        if (s1[i] < s2[i]) 
            return -1;
        else if (s1[i] > s2[i])
           return 1;
    }
   return 0;
} 

// Searches in the device list if we have a device with the mac address
// mac_address. Returns a pointer to it, or NULL if the list doesn't contain it.
DeviceList * getByMAC(DeviceList * dl, char mac_address[6]) {
    DeviceList * retour = NULL;
    while (dl != NULL) {
        //printf("cmp\n");
        //print_mac(dl->dl_mac_address);
        //print_mac(mac_address);
        if (maccmp(dl->dl_mac_address, mac_address)==0) {
            //printf("ok\n");
            retour = dl;
            return retour;
        }
        dl = dl->dl_next;
    }
            //printf("nok\n");
    return retour;
}

// Prints the mac addresses of all devices of the list and their corresponding
// RSSIs.
void print_lists(DeviceList * l) {
    while(l != NULL) {
        print_mac(l->dl_mac_address);
        RssiList * rl = l->dl_rssi_list;
        while (rl != NULL) {
            printf(" %d", rl->rl_rssi_value);
            rl = rl->rl_next;
        }
        l = l->dl_next;
        printf("\n");
    }
}

// because strcpy stops at \0 and at times the first byte of the
// mac address is 0x00, so nothing is copied
// copies the mac address "from" into "to"
void maccpy(char to[6], char from[6]) {
    int i;
    for (i=0; i<6; i++) {
        to[i] = from[i];
    }
}

//DEVICE
void add_device (DeviceList ** l , char mac_addr[6]) {
    DeviceList * new_dl = (DeviceList *) malloc(sizeof(DeviceList));
    maccpy(new_dl->dl_mac_address, mac_addr);
    new_dl->dl_rssi_list = NULL;
    //printf("device added : ");
    //print_mac(mac_addr);
    new_dl->dl_next = *l;
    *l = new_dl;
}
void clear_device_list (DeviceList ** l) {
    DeviceList * courant;
    DeviceList * tmp;
    courant = *l;
    while (courant->dl_next != NULL) {
        tmp = courant;
        courant = courant->dl_next;
        clear_rssi_list(tmp->dl_rssi_list);
        free(tmp);
    }
    free(courant);
}

int average_rssi(DeviceList * dl, char mac_addr[6]) {
    DeviceList * device = getByMAC(dl, mac_addr);
    if (device == NULL)
        return -95;

    int sum = 0, num = 0;
    RssiList * rssi = device->dl_rssi_list;
    while (rssi != NULL) {
        sum += rssi->rl_rssi_value;
        num++;
        rssi = rssi->rl_next;
    }
    return sum / num;
}


